package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.config.BigDataConfig;
import com.ruoyi.common.config.FtpConfig;
import com.ruoyi.common.core.domain.JSONObjectPro;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.enums.comlbs.DataDictTypeEnum;
import com.ruoyi.common.enums.comlbs.LocationStateEnum;
import com.ruoyi.common.enums.comlbs.PopMapEnum;
import com.ruoyi.common.enums.comlbs.ShortMsgTypeEnum;
import com.ruoyi.common.exception.BigDataException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.BigDataResponse;
import com.ruoyi.common.utils.http.HttpRequest;
import com.ruoyi.system.domain.AlarmType;
import com.ruoyi.system.domain.EquipmentManagement;
import com.ruoyi.system.domain.request.reportstatistics.*;
import com.ruoyi.system.domain.vo.common.DeviceGps;
import com.ruoyi.system.domain.vo.reportstatistics.*;
import com.ruoyi.system.service.IAlarmTypeService;
import com.ruoyi.system.service.IEquipmentManagementService;
import com.ruoyi.system.service.IReportStatisticsService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.utils.ComLbsUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 描述 统计报表Service实现类
 * 作者 ZhangPing
 * 创建时间 2023/8/17 15:34
 */
@Service
public class ReportStatisticsServiceImpl implements IReportStatisticsService {

    @Autowired
    private BigDataConfig bigDataConfig;
    @Autowired
    private FtpConfig ftpConfig;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private IEquipmentManagementService equipmentManagementService;
    @Autowired
    private IAlarmTypeService alarmTypeService;

    /**
     * 多媒体数据分页列表
     *
     * @param param
     * @return
     */
    @Override
    public Page<Photo> photoList(ReportStatisticsListParam param) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("pageIndex", param.getPageNum())
                .put("pageSize", param.getPageSize())
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime());
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyId", deptIdList);
        if (StringUtils.isNotEmpty(param.getNumberPlate())) {
            bigDataParams.put("numberPlate", Collections.singletonList(param.getNumberPlate()));
        }
        if (StringUtils.isNotEmpty(param.getDvo())) {
            bigDataParams.put("dvo", Collections.singletonList(param.getDvo()));
        }
        //远程调用接口
        BigDataResponse<JSONObject> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/photo/queryPage", bigDataParams, JSONObject.class);
        if (!response.isSuccess()) throw new BigDataException();
        JSONObject data = response.getData();
        int total = data.getIntValue("totalCount");
        List<JSONObject> dataItems = data.getList("dataItems", JSONObject.class);
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        //封装数据
        List<Photo> resultList = dataItems.stream().map(item -> {
            Photo photo = new Photo()
                    .setCompanyName(item.get("companyName").toString())
                    .setDvo(item.get("dvo").toString())
                    .setNumberPlate(item.get("numberPlate").toString())
                    .setChannelId((int) item.get("channelId"));

            if (item.get("MediaPath") != null) {
                photo.setPictureUrl(ftpConfig.ftp2Http(item.get("MediaPath").toString()));
            }

            JSONObject gpsData = item.getJSONObject("gpsData");
            DeviceGps deviceGps = ComLbsUtils.bigDataGpsFormat(gpsData);
            photo.setTime(deviceGps.getGdt()).setLocation(deviceGps.getLocation());
            photo.setLat(deviceGps.getLat());
            photo.setLng(deviceGps.getLng());
            photo.setSpd(deviceGps.getSpd());
            photo.setSatelliteCount(deviceGps.getSatelliteCount());
            if ( ObjectUtils.isNotEmpty(item.get("driverInfo"))) {
                JSONObject driverJson = item.getJSONObject("driverInfo");
                photo.setDriverName(driverJson.getString("driverName").toString());
            }


            return photo;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    /**
     * 车辆里程统计
     *
     * @param param
     * @return
     */
    @Override
    public Page<MileageStatistics> deviceMileageList(ReportStatisticsListParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("pageIndex", param.getPageNum())
                .put("pageSize", param.getPageSize())
                .put("startTime", param.getStartTime() + " 00:00:00")
                .put("endTime", DateUtils.addDay(param.getEndTime() + " 23:59:59", 1));
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyId", deptIdList);
        if (StringUtils.isNotEmpty(param.getNumberPlate())) {
            bigDataParams.put("numberPlate", Collections.singletonList(param.getNumberPlate()));
        }
        if (StringUtils.isNotEmpty(param.getDvo())) {
            bigDataParams.put("dvo", Collections.singletonList(param.getDvo()));
        }
        //远程调用接口
        String url = export ? "/deviceMileage/queryDailyList" : "/deviceMileage/queryDailyPage";
        BigDataResponse<JSONObject> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + url, bigDataParams, JSONObject.class);
        if (!response.isSuccess()) throw new BigDataException();
        JSONObject data = response.getData();
        int total = data.getIntValue("totalCount");
        List<JSONObject> dataItems = data.getList("dataItems", JSONObject.class);
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        //封装数据
        List<MileageStatistics> resultList = dataItems.stream().map(item -> {
            Long companyId = Long.parseLong(item.getString("companyId"));
            MileageStatistics mileageStatistics = new MileageStatistics()
                    .setCompanyId(companyId)
                    .setCompanyName(item.getString("companyName"))
                    .setCompanyShortName(deptMap.get(companyId) == null ? "" : deptMap.get(companyId))
                    .setDvo(item.getString("dvo"))
                    .setNumberPlate(item.getString("numberPlate"))
                    .setMileage(item.getIntValue("mileage"))
                    .setOilConsumption(ComLbsUtils.round45(item.get("oilConsumption")))
                    .setDriverMinutes(ComLbsUtils.round45(item.get("driverMinutes")))
                    .setKilometer(ComLbsUtils.round45(item.get("kilometre")));
            if (item.get("day") != null) mileageStatistics.setDay(new Date((long) item.get("day")));
            return mileageStatistics;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    /**
     * 车辆里程统计汇总导出
     *
     * @param param
     * @return
     */
    @Override
    public List<MileageStatistics> deviceMileageListSummaryExport(ReportStatisticsListParam param) {
        Page<MileageStatistics> page = deviceMileageList(param, true);
        //按车牌号汇总导出
        List<MileageStatistics> resultList = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(page.getList())) {
            page.getList().stream().collect(Collectors.groupingBy(MileageStatistics::getNumberPlate)).forEach((numberPlate, list) -> {
                MileageStatistics item = list.get(0)
                        .setDay(null)
                        .setMileage(list.stream().mapToInt(MileageStatistics::getMileage).sum())
                        .setOilConsumption(ComLbsUtils.round45(list.stream().mapToDouble(MileageStatistics::getOilConsumption).sum()))
                        .setDriverMinutes(ComLbsUtils.round45(list.stream().mapToDouble(MileageStatistics::getDriverMinutes).sum()))
                        .setKilometer(ComLbsUtils.round45(list.stream().mapToDouble(MileageStatistics::getKilometer).sum()));
                resultList.add(item);
            });
        }
        return resultList;
    }

    /**
     * 车辆里程明细
     *
     * @param param
     * @return
     */
    @Override
    public Page<MileageStatistics> deviceMileageDetailList(ReportStatisticsListParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime());
        if (!export) {
            bigDataParams.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyId", deptIdList);
        if (StringUtils.isNotEmpty(param.getNumberPlate())) {
            bigDataParams.put("numberPlate", Collections.singletonList(param.getNumberPlate()));
        }
        //远程调用接口
        BigDataResponse<Map<String, Object>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/deviceMileage/queryDeviceDetail", bigDataParams, Map.class);
        if (!response.isSuccess()) throw new BigDataException();
        Map<String, Object> data = response.getData();
        int total = (int) data.get("totalCount");
        List<Map<String, Object>> dataItems = (List<Map<String, Object>>) data.get("dataItems");
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        //封装数据
        List<MileageStatistics> resultList = dataItems.stream().map(item -> {
            Long companyId = Long.parseLong(item.get("companyId").toString());
            MileageStatistics mileageStatistics = new MileageStatistics()
                    .setCompanyId(companyId)
                    .setCompanyName(item.get("companyName").toString())
                    .setCompanyShortName(deptMap.get(companyId) == null ? "" : deptMap.get(companyId))
                    .setDvo(item.get("dvo").toString())
                    .setNumberPlate(item.get("numberPlate").toString())
                    .setMileage((int) item.get("mileage"))
                    .setDriverMinutes(ComLbsUtils.round45(item.get("driverMinutes")))
                    .setKilometer(ComLbsUtils.round45(item.get("kilometre")));
            if (item.get("time") != null) mileageStatistics.setDay(DateUtils.parseDate(item.get("time")));
            return mileageStatistics;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    /**
     * 历史轨迹明细
     *
     * @param param
     * @return
     */
    @Override
    public Page<Trajectory> trajectoryHistoryList(TrajectoryParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("dvo", param.getDvo())
                .put("spd", param.getSpeed())
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime());
        if (!export) {
            bigDataParams.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }
        //判断查询设备是不是在权限范围内
        EquipmentManagement equipment = equipmentManagementService.getByDeviceId(param.getDvo());
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        if (equipment == null || !deptMap.keySet().contains(equipment.getCompanyId())) {
            throw new ServiceException("设备不存在或无设备权限");
        }
        //远程调用接口
        BigDataResponse<JSONObject> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsRelationData/queryGpsRelationPage", bigDataParams, JSONObject.class);
        if (!response.isSuccess()) throw new BigDataException();
        JSONObject data = response.getData();
        int total = data.getIntValue("totalCount");
        List<JSONObject> dataItems = data.getList("dataItems", JSONObject.class);
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        //封装数据
        List<Trajectory> resultList = dataItems.stream().map(item -> {
            Trajectory trajectory = new Trajectory()
                    .setCompanyName(item.getString("companyName"))
                    .setCompanyShortName(ObjectUtils.isEmpty(item.get("companyId")) ? "" : deptMap.get(item.getLongValue("companyId")))
                    .setDvo(item.getString("dvo"))
                    .setNumberPlate(item.getString("numberPlate"))
                    .setSpeed(item.getIntValue("spd"))
                    .setLng(item.getDoubleValue("lng"))
                    .setLat(item.getDoubleValue("lat"));
            if (item.get("poi") != null) {
                trajectory.setLocation(item.getJSONObject("poi").getString("ars"));
            }
            if (item.get("gte") != null) {
                trajectory.setTime(new Date(item.getLongValue("gte")));
            }

            String s;
            //卫星数量
            Map popMap = (HashMap) item.get("pop");
            s = PopMapEnum.SatelliteCount.getCode().toString();
            if (popMap.containsKey(s)) {
                trajectory.setSatelliteCount(Integer.parseInt(popMap.get(s).toString()));
            } else {
                trajectory.setSatelliteCount(0);
            }
            //信号强度
            s = PopMapEnum.SignalIntensity.getCode().toString();
            if (popMap.containsKey(s)) {
                trajectory.setSignalIntensity(Integer.parseInt(popMap.get(s).toString()));
            } else {
                trajectory.setSignalIntensity(0);
            }

            // 以下为北三字段
            //发送方id
            s = PopMapEnum.SendId.getCode().toString();
            if (popMap.containsKey(s)) {
                trajectory.setSendId(Long.parseLong(popMap.get(s).toString()));
            }
            //接收方id
            s = PopMapEnum.ReceiveId.getCode().toString();
            if (popMap.containsKey(s)) {
                trajectory.setReceiveId(Long.parseLong(popMap.get(s).toString()));
            }
            //定位状态
            s = PopMapEnum.LocationState.getCode().toString();
            if (popMap.containsKey(s)) {
                int i = Integer.parseInt(popMap.get(s).toString());
                LocationStateEnum locationStateEnum = LocationStateEnum.fromInt(i);
                if (locationStateEnum != null) {
                    trajectory.setLocationState(locationStateEnum.getText());
                }
            }
            //短报文类型
            s = PopMapEnum.ShortMsgType.getCode().toString();
            if (popMap.containsKey(s)) {
                int i = Integer.parseInt(popMap.get(s).toString());
                ShortMsgTypeEnum shortMsgTypeEnum = ShortMsgTypeEnum.fromInt(i);
                if (shortMsgTypeEnum != null) {
                    trajectory.setShortMsgType(shortMsgTypeEnum.getText());
                }
            }
            //短报文内容
            s = PopMapEnum.ShortMsg.getCode().toString();
            if (popMap.containsKey(s)) {
                trajectory.setShortMsg(popMap.get(s).toString());
            }
            //传感器数组
            s = PopMapEnum.SensorList.getCode().toString();
            if (popMap.containsKey(s)) {
                trajectory.setSensorList(JSON.parseArray(popMap.get(s).toString()));
            }
            //高程
            if (item.get("hgt") != null) {
                trajectory.setHgt(Integer.parseInt(item.get("hgt").toString()));
            }
            return trajectory;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    @Override
    public Page<DeviceOnline> deviceOnlineList(ReportStatisticsListParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("numberPlate", param.getNumberPlate())
                .put("dvo", param.getDvo())
                .put("startTime", param.getStartTime())
                .put("endTime", DateUtils.addDay(param.getEndTime(), 1));
        if (!export) {
            bigDataParams.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyId", deptIdList);
        //远程调用接口
        BigDataResponse<JSONObject> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/deviceOnlineDetail/queryDeviceOnlineDetailPage", bigDataParams, JSONObject.class);
        if (!response.isSuccess()) throw new BigDataException();
        JSONObject data = response.getData();
        int total = data.getIntValue("totalCount");
        List<JSONObject> dataItems = data.getList("dataItems", JSONObject.class);
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        //封装数据
        List<DeviceOnline> resultList = dataItems.stream().map(item -> {
            DeviceOnline deviceOnline = new DeviceOnline()
                    .setCompanyName(item.getString("companyName"))
                    .setCompanyShortName(ObjectUtils.isEmpty(item.get("companyId")) ? "" : deptMap.get(item.getLongValue("companyId")))
                    .setDvo(item.getString("dvo"))
                    .setNumberPlate(item.getString("numberPlate"))
                    .setOnlineMinutes(DateUtils.timeDistance((long) (item.getDoubleValue("onlineMinutes") * 60 * 1000)));
            if (item.get("day") != null) {
                deviceOnline.setDay(DateUtils.parseDate(item.getString("day")));
            }
            if (item.get("startTime") != null) {
                deviceOnline.setStartTime(DateUtils.parseDate(item.getString("startTime")));
            }
            if (item.get("endTime") != null) {
                deviceOnline.setEndTime(DateUtils.parseDate(item.getString("endTime")));
            }
            return deviceOnline;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    /**
     * 报警统计
     *
     * @return
     */
    @Override
    public Page<AlarmStatistics> deviceAlarmList(DeviceAlarmListParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("startTime", param.getStartTime())
                .put("endTime", DateUtils.addDay(param.getEndTime(), 1));
        if (!export) {
            bigDataParams.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }

        //获取指定公司的告警类型Map
        Map<Integer, AlarmType> alarmTypeMap = alarmTypeService.getUserAlarmTypeMap();
        //封装告警类型集合参数
        List<Integer> alarmTypes = new ArrayList<>(alarmTypeMap.keySet());
        if (param.getLevel() != null) {
            alarmTypes.retainAll(alarmTypeService.alarmLevelToAlarmTypeList(param.getLevel()));
        }
        if (param.getType() != null) {
            alarmTypes.retainAll(Collections.singletonList(param.getType()));
        }
        if (CollectionUtils.isEmpty(alarmTypes)) {
            return new Page<>(0, new ArrayList<>());
        }
        bigDataParams.put("alarmTypes", alarmTypes);

        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyId", deptIdList);

        if (StringUtils.isNotEmpty(param.getNumberPlate())) {
            bigDataParams.put("numberPlate", param.getNumberPlate());
        }
        if (param.getSource() != null) {
            bigDataParams.put("src", param.getSource());
        }
        //远程调用接口
        BigDataResponse<Map<String, Object>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/deviceAlarmData/queryDailyAlarmCountPage", bigDataParams, Map.class);
        if (!response.isSuccess()) throw new BigDataException();
        Map<String, Object> data = response.getData();
        int total = (int) data.get("totalCount");
        List<Map<String, Object>> dataItems = (List<Map<String, Object>>) data.get("dataItems");
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));

        //封装数据
        List<AlarmStatistics> resultList = dataItems.stream().map(item -> {
            AlarmStatistics statistics = new AlarmStatistics()
                    .setType((Integer) item.get("ate"))
                    .setCompanyId(Long.valueOf((String) item.get("companyId")))
                    .setCompanyName((String) item.get("companyName"))
                    .setCompanyShortName(ObjectUtils.isEmpty(item.get("companyId")) ? "" : deptMap.get(Long.parseLong(item.get("companyId").toString())))
                    .setNumberPlate((String) item.get("numberPlate"))
                    .setDeviceId((String) item.get("dvo"))
                    .setCount((Integer) item.get("count"))
                    .setMinutes(ComLbsUtils.round45(item.get("mins")))
                    .setSource((Integer) item.get("src"))
                    .setSourceName(DictUtils.getDictLabel("source", (Integer) item.get("src")));
            //告警类型、等级
            AlarmType alarmType = AlarmType.toCustomLevelModel(alarmTypeMap.get((Integer) item.get("ate")));
            statistics.setName(alarmType.getName())
                    .setLevel(alarmType.getLevel())
                    .setLevelName(alarmType.getLevelName());
            if (item.get("day") != null) {
                statistics.setTime(new Date((long) item.get("day")));
            }
            return statistics;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    /**
     * 报警明细
     *
     * @param param
     * @return
     */
    @Override
    public Page<AlarmDetail> deviceAlarmDetailList(DeviceAlarmListParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime());
        if (!export) {
            bigDataParams.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }

        //获取指定公司的告警类型Map
        Map<Integer, AlarmType> alarmTypeMap = alarmTypeService.getUserAlarmTypeMap();
        //封装告警类型集合参数
        List<Integer> alarmTypes = new ArrayList<>(alarmTypeMap.keySet());
        if (param.getLevel() != null) {
            alarmTypes.retainAll(alarmTypeService.alarmLevelToAlarmTypeList(param.getLevel()));
        }
        if (param.getType() != null) {
            alarmTypes.retainAll(Collections.singletonList(param.getType()));
        }
        if (CollectionUtils.isEmpty(alarmTypes)) {
            return new Page<>(0, new ArrayList<>());
        }
        bigDataParams.put("alarmTypes", alarmTypes);

        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyId", deptIdList);
        if (StringUtils.isNotEmpty(param.getNumberPlate())) {
            bigDataParams.put("numberPlate", param.getNumberPlate());
        }
        if (param.getSource() != null) {
            bigDataParams.put("src", param.getSource());
        }
        //远程调用接口
        BigDataResponse<List<JSONObject>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/deviceAlarmData/queryAlarmCount", bigDataParams,
                new TypeReference<List<JSONObject>>() {
                }.getType());
        if (!response.isSuccess()) throw new BigDataException();
        List<JSONObject> dataItems = response.getData();
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));

        List<AlarmDetail> resultList = dataItems.stream().map(item -> {
            AlarmDetail detail = new AlarmDetail()
                    .setCompanyId(item.getLong("companyId"))
                    .setCompanyName(item.getString("companyName"))
                    .setCompanyShortName(ObjectUtils.isEmpty(item.get("companyId")) ? "" : deptMap.get(item.getLong("companyId")))
                    .setVehicleName(item.getString("vehicleName"))
                    .setNumberPlate(item.getString("numberPlate"))
                    .setAmc(item.getString("amc"))
                    .setAlarmLocation(item.getString("address"))
                    .setDeviceId(item.getString("dvo"))
                    .setRuleName(item.getString("ruleName"))
                    .setSpeed(item.getIntValue("spd"))
                    .setLng(item.getDoubleValue("lng"))
                    .setLat(item.getDoubleValue("lat"))
                    .setSource(item.getIntValue("src"))
                    .setSourceName(DictUtils.getDictLabel("source", item.getIntValue("src")))
                    .setTimes(StringUtils.isEmpty(item.get("times").toString()) ? 0 : item.getIntValue("times"));
            if (item.get("adt") != null) detail.setTime(DateUtils.parseDate(item.getString("adt")));
            if (item.get("endTime") != null) detail.setEndTime(DateUtils.parseDate(item.getString("endTime")));
            if (detail.getTime() != null && detail.getEndTime() != null) {
                detail.setDuration(String.format("%.1f", (detail.getEndTime().getTime() - detail.getTime().getTime()) / 1000 / 60D));
            }
            //告警类型、等级
            AlarmType alarmType = AlarmType.toCustomLevelModel(alarmTypeMap.get(item.getIntValue("ate")));
            detail.setType(alarmType.getType())
                    .setName(alarmType.getName())
                    .setLevel(alarmType.getLevel())
                    .setLevelName(alarmType.getLevelName());
            return detail;
        }).collect(Collectors.toList());
        return new Page<>(response.getTotalCount(), resultList);
    }

    /**
     * 公司整点上线率
     *
     * @param param
     * @return
     */
    @Override
    public Page<CompanyHourlyOnlineRate> companyHourlyOnlineRate(CompanyHourlyOnlineRateParam param, boolean export) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("startTime", param.getStartTime())
                .put("endTime", DateUtils.addDay(param.getEndTime(), 1));
        if (!export) {
            bigDataParams.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        bigDataParams.put("companyIds", deptIdList);
        //远程调用接口
        BigDataResponse<List<JSONObject>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsData/queryCarOnlineDay", bigDataParams,
                new TypeReference<List<JSONObject>>() {
                }.getType());
        if (!response.isSuccess()) throw new BigDataException();
        List<JSONObject> dataItems = response.getData();
        if (ObjectUtils.isEmpty(dataItems)) return new Page<>();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        List<CompanyHourlyOnlineRate> resultList = dataItems.stream().map(item -> {
            Long companyId = Long.parseLong(item.get("companyId").toString());
            String companyName = ObjectUtils.isEmpty(deptMap.get(companyId)) ? "" : deptMap.get(companyId);
            CompanyHourlyOnlineRate onlineRate = new CompanyHourlyOnlineRate()
                    .setNetworkCar(item.getIntValue("networkCar"))
                    .setOnlineCar(item.getIntValue("onlineCar"))
                    .setOnlineRate(item.getString("onlineRate"))
                    .setCompanyId(companyId)
                    .setCompanyName(companyName)
                    .setCompanyShortName(companyName);
            if (item.get("time") != null) {
                onlineRate.setTime(DateUtils.parseDate(item.get("time")));
            }
            return onlineRate;
        }).collect(Collectors.toList());
        return new Page<>(response.getTotalCount(), resultList);
    }

    /**
     * 公司整点上线率汇总导出
     *
     * @param param
     * @return
     */
    @Override
    public List<CompanyHourlyOnlineRateSummary> companyHourlyOnlineRateSummaryExport(CompanyHourlyOnlineRateParam param) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("startTime", param.getStartTime())
                .put("endTime", DateUtils.addSeconds(param.getEndTime(), 1))
                .put("companyIds", deptService.selectPermissionDeptId(param.getCompanyId()));
        //远程调用接口
        BigDataResponse<List<JSONObject>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsData/queryCarOnlineDay", bigDataParams,
                new TypeReference<List<JSONObject>>() {
                }.getType());
        if (!response.isSuccess()) throw new BigDataException();
        List<JSONObject> dataItems = response.getData();
        if (ObjectUtils.isEmpty(dataItems)) return Collections.emptyList();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        List<CompanyHourlyOnlineRate> dataList = dataItems.stream().map(item -> {
            Long companyId = Long.parseLong(item.get("companyId").toString());
            String companyName = ObjectUtils.isEmpty(deptMap.get(companyId)) ? "" : deptMap.get(companyId);
            CompanyHourlyOnlineRate onlineRate = new CompanyHourlyOnlineRate()
                    .setNetworkCar(item.getIntValue("networkCar"))
                    .setOnlineCar(item.getIntValue("onlineCar"))
                    .setOnlineRate(item.getString("onlineRate"))
                    .setCompanyId(companyId)
                    .setCompanyName(companyName)
                    .setCompanyShortName(companyName);
            if (item.get("time") != null) {
                onlineRate.setTime(DateUtils.parseDate(item.get("time")));
            }
            return onlineRate;
        }).collect(Collectors.toList());
        Map<Long, List<CompanyHourlyOnlineRate>> companyMap = dataList.stream().collect(Collectors.groupingBy(CompanyHourlyOnlineRate::getCompanyId));
        List<CompanyHourlyOnlineRateSummary> resultList = new ArrayList<>();
        for (Long companyId : companyMap.keySet()) {
            List<CompanyHourlyOnlineRate> list = companyMap.get(companyId);
            CompanyHourlyOnlineRate item = list.get(0);
            int sum = list.stream().mapToInt(i -> Integer.parseInt(i.getOnlineRate().replace("%", ""))).sum();
            resultList.add(new CompanyHourlyOnlineRateSummary(item.getCompanyName(), ComLbsUtils.round45(sum * 1.0 / list.size()) + "%"));
        }
        return resultList;
    }

    /**
     * 公司整点上线率详情
     *
     * @param param
     * @return
     */
    @Override
    public List<CompanyHourlyOnlineDetail> companyHourlyOnlineDetail(CompanyHourlyOnlineDetailParam param) {
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        //远程调用接口
        JSONObjectPro httpParam = new JSONObjectPro()
                .put("companyIds", deptIdList)
                .put("numberPlate", param.getNumberPlate())
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime());
        BigDataResponse<List<CompanyHourlyOnlineDetail>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsData/queryCarOnlineHour",
                httpParam, new TypeReference<List<CompanyHourlyOnlineDetail>>() {
                }.getType());
        if (!response.isSuccess()) throw new BigDataException();
        return response.getData();
    }

    /**
     * 车辆状态统计列表
     *
     * @param param
     * @return
     */
    @Override
    public Page<DeviceStatusStatistics> deviceStatusStatisticsList(StatusStatisticsListParam param, boolean export) {
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());
        //远程调用接口
        JSONObjectPro httpParam = new JSONObjectPro()
                .put("companyId", deptIdList)
                .put("status", param.getStatus());
        if (!export) {
            httpParam.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }
        if (StringUtils.isNotEmpty(param.getNumberPlate())) {
            httpParam.put("numberPlate", param.getNumberPlate());
        }
        BigDataResponse<JSONObject> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsData/queryLastGpsStatus", httpParam, JSONObject.class);
        if (!response.isSuccess()) throw new BigDataException();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getShortName));
        JSONObject data = response.getData();
        List<JSONObject> dataItems = data.getList("dataItems", JSONObject.class);
        int total = (int) data.get("totalCount");
        //组装数据
        List<DeviceStatusStatistics> resultList = dataItems.stream().map(item -> {
            Long companyId = item.getLongValue("companyId");
            DeviceStatusStatistics statistics = new DeviceStatusStatistics()
                    .setKilometer(ComLbsUtils.round45(item.get("kilometer")))
                    .setNumberPlate(item.getString("numberPlate"))
                    .setSpd(item.getIntValue("spd"))
                    .setMie(item.getIntValue("mie"))
                    .setAddress(item.getString("address"))
                    .setCompanyId(companyId)
                    .setCompanyName(item.getString("companyName"))
                    .setCompanyShortName(StringUtils.isEmpty(deptMap.get(companyId)) ? "" : deptMap.get(companyId))
                    .setVehicleStatus(ComLbsUtils.getVehicleStatus(ComLbsUtils.bigDataGpsFormat(item)).getText());
            if (ObjectUtils.isNotEmpty(item.get("gdt"))) {
                statistics.setGdt(DateUtils.parseDate(item.get("gdt").toString()));
            }
            return statistics;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }

    /**
     * 人脸识别统计列表
     *
     * @param param
     * @param export
     * @return
     */
    public Page<PersonFaceResultStatistics> personFaceResultList(PersonFaceParam param, boolean export) {
        //获取有权限的公司ID
        List<Long> deptIdList = deptService.selectPermissionDeptId(param.getCompanyId());

        JSONObjectPro httpJson = new JSONObjectPro()
                .put("companyIds", deptIdList)
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime());
        if (!export) {
            httpJson.put("pageIndex", param.getPageNum()).put("pageSize", param.getPageSize());
        }
        if (ObjectUtils.isNotEmpty(param.getNumberPlate())) httpJson.put("numberPlate", param.getNumberPlate());
        if (ObjectUtils.isNotEmpty(param.getResult())) httpJson.put("result", param.getResult());

        //调用大数据的接口获取数据
        BigDataResponse<List<JSONObject>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/faceRecognition/queryFaceRecognition",
                httpJson, new TypeReference<List<JSONObject>>() {
                }.getType());
        if (!response.isSuccess()) throw new BigDataException();
        List<JSONObject> detail = response.getData();
        Map<Long, String> deptMap = deptService.selectDeptList(new SysDept()).stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName));
        //封装数据
        int total = response.getTotalCount();
        List<PersonFaceResultStatistics> resultList = detail.stream().map(data -> {
            PersonFaceResultStatistics result = new PersonFaceResultStatistics();
            result.setDriverName(data.get("driverName").toString());
            result.setNumberPlate(data.get("numberPlate").toString());
            result.setResult((Integer) data.get("result"));
            long compId = Long.parseLong(data.get("companyId").toString());
            String shortName = deptMap.get(compId);
            if (shortName != null) {
                result.setComapnyShortName(shortName);
            } else {
                result.setComapnyShortName("");
            }
            String resultStr = DictUtils.getDictLabel(DataDictTypeEnum.SUCCESS_FAIL.getText(), data.get("result").toString());
            result.setResultStr(resultStr);
            if (data.get("pte") != null) {
                Date time = DateUtils.parseDate(data.get("pte").toString());
                result.setTime(time);
            }
            String id = data.get("companyId").toString();
            if (deptMap.get(Long.parseLong(id)) != null) {
                result.setCompanyName(deptMap.get(Long.parseLong(id)));
            } else {
                result.setCompanyName("");
            }
            result.setPicture(ftpConfig.ftp2Http(data.get("path").toString()));
            return result;
        }).collect(Collectors.toList());
        return new Page<>(total, resultList);
    }
}
